#include "preHeader.h"
#include "GameServerSession.h"
#include "GameServerSessionHandler.h"
#include "SocialServerSession.h"
#include "ClientMgr.h"
#include "MapServerMgr.h"
#include "ServerMaster.h"
#include "GateServer.h"
#include "network/ConnectionManager.h"
#include "Game/TransMgr.h"

GameServerSession::GameServerSession()
: Session("GameServerSession")
, m_serverId(0)
, m_sn(0)
{
}

GameServerSession::~GameServerSession()
{
}

void GameServerSession::CheckConnection()
{
	const auto& connPrePtr = GetConnection();
	if (connPrePtr && connPrePtr->IsActive()) {
		return;
	}
	if (!IsStatus(Idle)) {
		return;
	}

	auto& cfg = IServerMaster::GetInstance().GetConfig();
	auto connPtr = sConnectionManager.NewConnection(*this);
	connPtr->AsyncConnect(
		cfg.GetString("GAME_SERVER", "HOST", "127.0.0.1"),
		cfg.GetString("GAME_SERVER", "PORT", "9998"));

	sSessionManager.AddSession(this);
}

void GameServerSession::TransPacket(uint32 acct, const INetPacket& pck)
{
	NetPacket trans(CGG_TRANS_CLIENT_PACKET);
	trans << acct;
	PushSendPacket(trans, pck);
}

int GameServerSession::HandlePacket(INetPacket *pck)
{
	return sGameServerSessionHandler.HandlePacket(this, *pck);
}

void GameServerSession::OnConnected()
{
	NetPacket req(CGG_REGISTER);
	PushSendPacket(req);
	Session::OnConnected();
}

void GameServerSession::OnShutdownSession()
{
	WLOG("Close GameServerSession [gateSN:%u].", m_sn);
	sMapServerMgr.ClearAllMapServers();
	sClientMgr.KickAllClient(LOGIN_ERROR_GATE_SERVER_OFFLINE);
	CancelReadyStatus();
	Session::OnShutdownSession();
}

void GameServerSession::DeleteObject()
{
	ClearRecvPacket();
	ClearShutdownFlag();
	SetStatus(Idle);
}

void GameServerSession::OnRecvPacket(INetPacket *pck)
{
	switch (pck->GetOpcode()) {
	case SGG_TRANS_CLIENT_PACKET:
		TransClientPacket(pck);
		delete pck;
		break;
	default:
		Session::OnRecvPacket(pck);
		break;
	}
}

void GameServerSession::TransClientPacket(INetPacket *pck) const
{
	auto pSession = sTransMgr.GetClient(pck->Read<uint32>());
	if (pSession != NULL) {
		pSession->PushSendPacket(pck->CastReadableStringView());
	}
}

void GameServerSession::TryAddMapServer(INetPacket& pck)
{
	uint32 msSN, gsIdx;
	std::string host, port;
	pck >> msSN >> gsIdx >> host >> port;
	auto pMapServer = sMapServerMgr.GetMapServer(msSN);
	if (pMapServer != NULL) {
		pMapServer->Reuse();
	} else {
		sMapServerMgr.AddMapServer(new MapServerSession(msSN, gsIdx, host, port));
	}
}

int GameServerSessionHandler::HandleRegisterResp(GameServerSession *pSession, INetPacket &pck)
{
	pck >> pSession->m_serverId >> pSession->m_sn;
	sSocialServerSession.SetGsGateSN(pSession->m_sn);

	std::string socialListenAddr, socialListenPort;
	pck >> socialListenAddr >> socialListenPort;
	sSocialServerSession.SetHostPort(socialListenAddr, socialListenPort);

	pck.Take(pSession->m_handlerFlags, sizeof(pSession->m_handlerFlags));
	for (uint16 i = 0, n = pck.Read<uint16>(); i < n; ++i) {
		pSession->TryAddMapServer(pck);
	}

	NLOG("Register to GameServer Success As [gateSN:%u].", pSession->m_sn);

	return SessionHandleSuccess;
}

int GameServerSessionHandler::HandleAddMapServer(GameServerSession *pSession, INetPacket &pck)
{
	pSession->TryAddMapServer(pck);
	return SessionHandleSuccess;
}

int GameServerSessionHandler::HandleRemoveMapServer(GameServerSession *pSession, INetPacket &pck)
{
	auto msSN = pck.Read<uint32>();
	auto pMapServer = sMapServerMgr.GetMapServer(msSN);
	if (pMapServer != NULL) {
		pMapServer->Cancel();
	}
	return SessionHandleSuccess;
}

int GameServerSessionHandler::HandlePushServerId(GameServerSession *pSession, INetPacket &pck)
{
	pck >> pSession->m_serverId;
	return SessionHandleSuccess;
}

int GameServerSessionHandler::HandlePushSocialListen(GameServerSession *pSession, INetPacket &pck)
{
	std::string socialListenAddr, socialListenPort;
	pck >> socialListenAddr >> socialListenPort;
	sSocialServerSession.SetHostPort(socialListenAddr, socialListenPort);
	return SessionHandleSuccess;
}

int GameServerSessionHandler::HandlePushPacketToAllClient(GameServerSession *pSession, INetPacket &pck)
{
	sClientMgr.BroadcastPacket2AllClient(pck.UnpackPacket());
	return SessionHandleSuccess;
}

int GameServerSessionHandler::HandleKickAccount(GameServerSession *pSession, INetPacket &pck)
{
	auto pClientSession = sClientMgr.GetClient(pck.Read<uint32>());
	if (pClientSession != NULL) {
		sClientMgr.KickClient(pClientSession, GErrorCode(pck.Read<int32>()));
	}
	return SessionHandleSuccess;
}

int GameServerSessionHandler::HandleKillAccount(GameServerSession *pSession, INetPacket &pck)
{
	auto pClientSession = sClientMgr.GetClient(pck.Read<uint32>());
	if (pClientSession != NULL) {
		sClientMgr.KillClient(pClientSession);
	}
	return SessionHandleSuccess;
}

int GameServerSessionHandler::HandlePushCharacter(GameServerSession *pSession, INetPacket &pck)
{
	auto pClientSession = sClientMgr.GetClient(pck.Read<uint32>());
	if (pClientSession != NULL) {
		auto charId = pck.Read<uint32>();
		if (charId != 0) {
			pClientSession->SetCharacterOnline(charId);
		} else {
			pClientSession->SetCharacterOffline();
		}
	}
	return SessionHandleSuccess;
}

int GameServerSessionHandler::HandlePushPlayer(GameServerSession *pSession, INetPacket &pck)
{
	auto pClientSession = sClientMgr.GetClient(pck.Read<uint32>());
	if (pClientSession != NULL) {
		auto msSN = pck.Read<uint32>();
		if (msSN != 0) {
			pClientSession->SetCharacterEnterMapServer(msSN);
		} else {
			pClientSession->SetCharacterLeaveMapServer();
		}
	}
	return SessionHandleSuccess;
}
